/**
 * MVR设备租赁平台 - HTTP请求封装
 * 基于uni.request封装，提供统一的API调用接口
 */

import { API_CONFIG } from './config.js'

/**
 * 统一的API请求封装服务
 * 基于uni.request封装，提供拦截器、错误处理、token管理等功能
 */
class HttpRequest {
  constructor() {
    this.baseURL = API_CONFIG.BASE_URL
    this.timeout = API_CONFIG.TIMEOUT
    this.requestInterceptors = []
    this.responseInterceptors = []
    this.isRefreshing = false // 防止重复刷新token
  }

  /**
   * 添加请求拦截器
   * @param {Function} handler 拦截处理函数
   */
  addRequestInterceptor(handler) {
    this.requestInterceptors.push(handler)
  }

  /**
   * 添加响应拦截器
   * @param {Function} successHandler 成功处理函数
   * @param {Function} errorHandler 错误处理函数
   */
  addResponseInterceptor(successHandler, errorHandler) {
    this.responseInterceptors.push({
      success: successHandler,
      error: errorHandler
    })
  }

  /**
   * 获取存储的token
   */
  getToken() {
    try {
      // 先尝试获取新的token键名
      let token = uni.getStorageSync(API_CONFIG.STORAGE_KEYS.TOKEN)
      
      // 如果没有，尝试获取旧的access_token（兼容性处理）
      if (!token) {
        token = uni.getStorageSync('access_token')
        if (token) {
          // 迁移到新的键名
          uni.setStorageSync(API_CONFIG.STORAGE_KEYS.TOKEN, token)
          uni.removeStorageSync('access_token')
          console.log('🔄 已迁移旧的access_token到新的token键名')
        }
      }
      
      return token || ''
    } catch (error) {
      console.error('获取Token失败:', error)
      return ''
    }
  }

  /**
   * 设置token
   * @param {String} token 访问令牌
   */
  setToken(token) {
    try {
      uni.setStorageSync(API_CONFIG.STORAGE_KEYS.TOKEN, token)
    } catch (error) {
      console.error('保存Token失败:', error)
    }
  }

  /**
   * 获取刷新token
   */
  getRefreshToken() {
    try {
      // 先尝试获取新的refresh_token键名
      let refreshToken = uni.getStorageSync(API_CONFIG.STORAGE_KEYS.REFRESH_TOKEN)
      
      // 如果没有，尝试获取可能的旧键名（兼容性处理）
      if (!refreshToken) {
        refreshToken = uni.getStorageSync('refreshToken')
        if (refreshToken) {
          // 迁移到新的键名
          uni.setStorageSync(API_CONFIG.STORAGE_KEYS.REFRESH_TOKEN, refreshToken)
          uni.removeStorageSync('refreshToken')
          console.log('🔄 已迁移旧的refreshToken到新的refresh_token键名')
        }
      }
      
      return refreshToken || ''
    } catch (error) {
      console.error('获取RefreshToken失败:', error)
      return ''
    }
  }

  /**
   * 设置刷新token
   * @param {String} refreshToken 刷新令牌
   */
  setRefreshToken(refreshToken) {
    try {
      uni.setStorageSync(API_CONFIG.STORAGE_KEYS.REFRESH_TOKEN, refreshToken)
    } catch (error) {
      console.error('保存RefreshToken失败:', error)
    }
  }

  /**
   * 清除所有token
   */
  clearTokens() {
    try {
      // 清除新的键名
      uni.removeStorageSync(API_CONFIG.STORAGE_KEYS.TOKEN)
      uni.removeStorageSync(API_CONFIG.STORAGE_KEYS.REFRESH_TOKEN)
      uni.removeStorageSync(API_CONFIG.STORAGE_KEYS.USER_INFO)
      
      // 清除可能的旧键名（兼容性处理）
      uni.removeStorageSync('access_token')
      uni.removeStorageSync('refreshToken')
      uni.removeStorageSync('user')
      
      console.log('🧹 已清除所有Token和用户信息')
    } catch (error) {
      console.error('清除Token失败:', error)
    }
  }

  /**
   * 构建完整URL
   * @param {String} url 相对路径
   */
  buildURL(url) {
    if (url.startsWith('http')) {
      return url
    }
    return `${this.baseURL}${url.startsWith('/') ? '' : '/'}${url}`
  }

  /**
   * 处理请求配置
   * @param {Object} config 请求配置
   */
  async processRequestConfig(config) {
    // 设置默认配置
    const requestConfig = {
      url: this.buildURL(config.url),
      method: config.method || 'GET',
      data: config.data || {},
      header: {
        'Content-Type': 'application/json',
        ...config.header
      },
      timeout: config.timeout || this.timeout
    }

    // 添加认证头
    const token = this.getToken()
    if (token) {
      requestConfig.header.Authorization = `Bearer ${token}`
    }

    // 应用请求拦截器
    let finalConfig = requestConfig
    for (const interceptor of this.requestInterceptors) {
      try {
        finalConfig = await interceptor(finalConfig)
      } catch (error) {
        console.error('请求拦截器错误:', error)
      }
    }

    return finalConfig
  }

  /**
   * 处理响应数据
   * @param {Object} response 响应对象
   */
  async processResponse(response) {
    // 应用响应拦截器
    let processedResponse = response
    for (const interceptor of this.responseInterceptors) {
      try {
        if (response.statusCode >= 200 && response.statusCode < 300) {
          if (interceptor.success) {
            processedResponse = await interceptor.success(processedResponse)
          }
        } else {
          if (interceptor.error) {
            processedResponse = await interceptor.error(processedResponse)
          }
        }
      } catch (error) {
        console.error('响应拦截器错误:', error)
      }
    }

    return processedResponse
  }

  /**
   * 发送HTTP请求
   * @param {Object} config 请求配置
   */
  async request(config) {
    try {
      const requestConfig = await this.processRequestConfig(config)
      
      return new Promise(async (resolve, reject) => {
        const response = await uni.request(requestConfig)
        
        // 将请求配置附加到响应对象，供拦截器使用
        response.config = requestConfig
        
        try {
          const processedResponse = await this.processResponse(response)
          
          if (processedResponse.statusCode >= 200 && processedResponse.statusCode < 300) {
            // 请求成功
            const result = processedResponse.data
            
            // 检查业务状态码
            if (result.code && result.code === API_CONFIG.STATUS_CODES.SUCCESS) {
              // 为了兼容性，我们返回完整的响应结构
              // 但在data中添加原始data，这样新旧代码都能工作
              const response = {
                ...result,
                originalData: result.data
              }
              resolve(response)
            } else {
              // 业务错误
              const error = new Error(result.message || '请求失败')
              error.code = result.code
              error.response = processedResponse
              reject(error)
            }
          } else {
            // HTTP状态码错误
            const error = new Error(this.getErrorMessage(processedResponse.statusCode))
            error.statusCode = processedResponse.statusCode
            error.response = processedResponse
            reject(error)
          }
        } catch (error) {
          reject(error)
        }
      })
    } catch (error) {
      console.error('请求发送失败:', error)
      throw error
    }
  }

  /**
   * 根据状态码获取错误信息
   * @param {Number} statusCode HTTP状态码
   */
  getErrorMessage(statusCode) {
    const errorMap = {
      400: '请求参数错误',
      401: '未授权，请重新登录',
      403: '拒绝访问',
      404: '请求资源不存在',
      405: '请求方法不允许',
      408: '请求超时',
      500: '服务器内部错误',
      502: '网关错误',
      503: '服务不可用',
      504: '网关超时'
    }
    
    return errorMap[statusCode] || `请求失败，状态码：${statusCode}`
  }

  /**
   * GET请求
   * @param {String} url 请求地址
   * @param {Object} params 请求参数
   * @param {Object} config 额外配置
   */
  get(url, params = {}, config = {}) {
    // 构建查询字符串
    if (Object.keys(params).length > 0) {
      const queryString = Object.entries(params)
        .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
        .join('&')
      url = `${url}${url.includes('?') ? '&' : '?'}${queryString}`
    }
    
    return this.request({
      url,
      method: 'GET',
      ...config
    })
  }

  /**
   * POST请求
   * @param {String} url 请求地址
   * @param {Object} data 请求数据
   * @param {Object} config 额外配置
   */
  post(url, data = {}, config = {}) {
    return this.request({
      url,
      method: 'POST',
      data,
      ...config
    })
  }

  /**
   * PUT请求
   * @param {String} url 请求地址
   * @param {Object} data 请求数据
   * @param {Object} config 额外配置
   */
  put(url, data = {}, config = {}) {
    return this.request({
      url,
      method: 'PUT',
      data,
      ...config
    })
  }

  /**
   * DELETE请求
   * @param {String} url 请求地址
   * @param {Object} config 额外配置
   */
  delete(url, config = {}) {
    return this.request({
      url,
      method: 'DELETE',
      ...config
    })
  }

  /**
   * 文件上传
   * @param {String} url 上传地址
   * @param {String} filePath 文件路径
   * @param {Object} formData 额外表单数据
   * @param {Object} config 配置选项
   */
  upload(url, filePath, formData = {}, config = {}) {
    return new Promise((resolve, reject) => {
      const token = this.getToken()
      const header = {
        ...config.header
      }
      
      if (token) {
        header.Authorization = `Bearer ${token}`
      }

      uni.uploadFile({
        url: this.buildURL(url),
        filePath: filePath,
        name: config.name || 'file',
        formData: formData,
        header: header,
        success: (response) => {
          try {
            const result = JSON.parse(response.data)
            if (result.code === API_CONFIG.STATUS_CODES.SUCCESS) {
              resolve(result.data)
            } else {
              reject(new Error(result.message || '上传失败'))
            }
          } catch (error) {
            reject(new Error('响应数据格式错误'))
          }
        },
        fail: (error) => {
          reject(error)
        }
      })
    })
  }
}

// 创建实例
const http = new HttpRequest()

// 添加请求拦截器
http.addRequestInterceptor((config) => {
  // 显示加载提示
  // uni.showLoading({
  //   title: '加载中...',
  //   mask: true
  // })
  
  console.log('发送请求:', config)
  return config
})

// 添加响应拦截器
http.addResponseInterceptor(
  // 成功响应处理
  (response) => {
    // 隐藏加载提示
    uni.hideLoading()
    console.log('请求成功:', response)
    return response
  },
  // 错误响应处理
  async (response) => {
    // 隐藏加载提示
    uni.hideLoading()
    
    console.error('请求错误:', response)
    
    // 处理token过期（但跳过refresh接口本身）
    if (response.statusCode === 401 && !response.config?.header?.['X-Skip-Auth-Interceptor']) {
      const refreshToken = http.getRefreshToken()
      if (refreshToken && !http.isRefreshing) {
        try {
          http.isRefreshing = true // 设置刷新标记
          console.log('🔄 Token过期，尝试刷新...')
          
          // 尝试刷新token，添加特殊标记避免再次触发拦截器
          const refreshResult = await http.request({
            url: '/auth/refresh',
            method: 'POST',
            data: {
              refreshToken: refreshToken
            },
            header: {
              'X-Skip-Auth-Interceptor': 'true' // 跳过认证拦截器
            }
          })
          
          console.log('✅ Token刷新成功:', refreshResult)
          
          // 更新token - 检查数据格式
          let newToken = null
          let newRefreshToken = null
          
          if (refreshResult.originalData) {
            newToken = refreshResult.originalData.token || refreshResult.originalData.access_token
            newRefreshToken = refreshResult.originalData.refresh_token
          } else if (refreshResult.data) {
            newToken = refreshResult.data.token || refreshResult.data.access_token
            newRefreshToken = refreshResult.data.refresh_token
          } else {
            newToken = refreshResult.token || refreshResult.access_token
            newRefreshToken = refreshResult.refresh_token
          }
          
          if (!newToken) {
            console.error('❌ Token刷新响应中没有找到新Token:', refreshResult)
            throw new Error('Token刷新响应格式错误')
          }
          
          http.setToken(newToken)
          if (newRefreshToken) {
            http.setRefreshToken(newRefreshToken)
          }
          
          console.log('🔄 Token已更新:', {
            newToken: newToken ? '存在' : '不存在',
            newRefreshToken: newRefreshToken ? '存在' : '不存在'
          })
          
          console.log('🔄 Token已更新，尝试重新发送原请求')
          
          // Token刷新成功后，重新发送原请求
          try {
            // 更新原请求配置中的Authorization头
            const originalConfig = { ...response.config }
            originalConfig.header.Authorization = `Bearer ${newToken}`
            
            console.log('🔄 重新发送原请求:', originalConfig.url)
            console.log('🔑 使用新Token:', newToken.substring(0, 20) + '...')
            
            // 重新发送请求
            const retryResponse = await uni.request(originalConfig)
            console.log('🔄 重试请求响应:', retryResponse)
            
            http.isRefreshing = false // 重置刷新标记
            
            // 检查重试请求的结果
            if (retryResponse.statusCode >= 200 && retryResponse.statusCode < 300) {
              console.log('✅ 重试请求成功')
              return retryResponse
            } else if (retryResponse.statusCode === 401) {
              console.log('❌ 重试请求仍然401，可能RefreshToken也过期了')
              // RefreshToken也过期了，需要重新登录
              http.clearTokens()
              uni.showToast({
                title: '登录已过期，请重新登录',
                icon: 'none'
              })
              setTimeout(() => {
                uni.reLaunch({
                  url: '/pages/login/index'
                })
              }, 1500)
              return retryResponse
            } else {
              console.log('❌ 重试请求失败，状态码:', retryResponse.statusCode)
              return retryResponse
            }
          } catch (retryError) {
            console.error('❌ 重试请求失败:', retryError)
            http.isRefreshing = false // 重置刷新标记
            
            // 重试失败，返回特殊响应让前端知道需要手动重试
            return {
              ...response,
              statusCode: 200, // 改为成功状态
              data: {
                code: 401,
                message: 'Token已刷新，但重试失败，请手动重试',
                needRetry: true
              }
            }
          }
        } catch (error) {
          console.log('❌ Token刷新失败:', error)
          http.isRefreshing = false // 重置刷新标记
          // 刷新失败，清除token并跳转到登录页
          http.clearTokens()
          uni.showToast({
            title: '登录已过期，请重新登录',
            icon: 'none'
          })
          
          setTimeout(() => {
            uni.reLaunch({
              url: '/pages/login/index'
            })
          }, 1500)
        }
      } else if (http.isRefreshing) {
        // 正在刷新token，返回特殊响应让前端等待
        console.log('🔄 Token正在刷新中，请稍后重试...')
        return {
          ...response,
          statusCode: 200,
          data: {
            code: 401,
            message: 'Token正在刷新中，请稍后重试',
            needRetry: false // 不需要重试，避免无限循环
          }
        }
      } else {
        // 没有刷新token，直接跳转到登录页
        http.clearTokens()
        uni.showToast({
          title: '请先登录',
          icon: 'none'
        })
        
        setTimeout(() => {
          uni.reLaunch({
            url: '/pages/login/index'
          })
        }, 1500)
      }
    } else {
      // 其他错误显示提示
      uni.showToast({
        title: http.getErrorMessage(response.statusCode),
        icon: 'none',
        duration: 1200
      })
    }
    
    return response
  }
)

// HTTP错误信息映射
function getHttpErrorMessage(statusCode) {
  const errorMessages = {
    400: '请求参数错误',
    401: '未授权访问',
    403: '禁止访问',
    404: '请求资源不存在',
    405: '请求方法不允许',
    408: '请求超时',
    500: '服务器内部错误',
    502: '网关错误',
    503: '服务暂不可用',
    504: '网关超时'
  }
  
  return errorMessages[statusCode] || `请求失败 (${statusCode})`
}

// Token过期处理
function handleTokenExpired() {
  // 清除本地存储的认证信息
  uni.removeStorageSync(CONFIG.STORAGE_KEYS.TOKEN)
  uni.removeStorageSync(CONFIG.STORAGE_KEYS.REFRESH_TOKEN)
  uni.removeStorageSync(CONFIG.STORAGE_KEYS.USER_INFO)
  
  // 跳转到登录页
  uni.showToast({
    title: '登录已过期，请重新登录',
    icon: 'none'
  })
  
  setTimeout(() => {
    // #ifdef MP-WEIXIN
    uni.reLaunch({
      url: '/pages/login/index'
    })
    // #endif
    
    // #ifdef APP-PLUS
    uni.reLaunch({
      url: '/pages/login/index'
    })
    // #endif
    
    // #ifdef H5
    uni.reLaunch({
      url: '/pages/login/index'
    })
    // #endif
  }, 1500)
}

// 网络状态检查
export function checkNetworkStatus() {
  return new Promise((resolve) => {
    uni.getNetworkType({
      success: (res) => {
        resolve(res.networkType !== 'none')
      },
      fail: () => {
        resolve(false)
      }
    })
  })
}

// 平台适配的上传文件方法
export function uploadFile(options) {
  const { filePath, name = 'file', formData = {}, ...otherOptions } = options
  
  return new Promise((resolve, reject) => {
    // 检查网络状态
    checkNetworkStatus().then((isOnline) => {
      if (!isOnline) {
        uni.showToast({
          title: '网络不可用',
          icon: 'none'
        })
        reject(new Error('网络不可用'))
        return
      }
      
      const token = uni.getStorageSync(CONFIG.STORAGE_KEYS.TOKEN)
      const header = token ? { 'Authorization': `Bearer ${token}` } : {}
      
      uni.uploadFile({
        url: `${CONFIG.BASE_URL}${options.url}`,
        filePath,
        name,
        formData,
        header,
        ...otherOptions,
        success: (res) => {
          try {
            const data = JSON.parse(res.data)
            if (data.code === 200 || data.code === 0) {
              resolve(data)
            } else {
              reject(new Error(data.message || '上传失败'))
            }
          } catch (error) {
            reject(new Error('上传响应解析失败'))
          }
        },
        fail: (error) => {
          let errorMessage = '上传失败'
          
          // #ifdef MP-WEIXIN
          if (error.errMsg && error.errMsg.includes('uploadFile:fail')) {
            errorMessage = '文件上传失败，请检查网络'
          }
          // #endif
          
          // #ifdef APP-PLUS
          if (error.errMsg && error.errMsg.includes('timeout')) {
            errorMessage = '上传超时，请重试'
          }
          // #endif
          
          reject(new Error(errorMessage))
        }
      })
    })
  })
}

export default http 